<template>
  <el-select
    v-model="value"
    v-el-select-loadMore="loadMore"
    multiple
    :disabled="disabled"
    filterable
    :filter-method="filterMethod"
    @visible-change="blurFunction"
  >
    <el-option
      v-for="(item, key) in options"
      :key="key"
      :label="item[props.label]"
      :value="formatSelectVal(item[props.value])"
    />
    <el-option
      v-for="(item, key) in hiddenList"
      v-show="false"
      :key="key + item[props.label]"
      :label="item[props.label]"
      :value="formatSelectVal(item[props.value])"
    />
  </el-select>
</template>

<script lang="ts">
import { Prop, Options, Vue, Model, Watch } from "vue-property-decorator";
import SelectTree from "/@/components/CommonCo/el-tree-select.vue";
@Options({
  name: "MultiSelect",
  components: {
    SelectTree
  }
})
export default class MultiSelect extends Vue {
  // 设置下拉框数据格式字段
  @Prop({
    type: Object,
    default: function () {
      return { label: "label", value: "value", key: "value" };
    }
  })
  private props!: any;

  // 父组件传入下拉框数据
  @Prop({
    type: Array,
    default: function () {
      return [];
    }
  })
  private selectList!: any[];

  private hiddenList: any[] = [];
  // 下拉框临时数据
  private tempList: any[] = [];
  // 监听下拉框数据变化
  @Watch("selectList", { immediate: true })
  private setOptions(val: any) {
    this.tempList = val.concat();
    if (val.length > 20) {
      this.options = Array.from(new Set(this.tempList.splice(0, 20)));
    } else {
      this.options = Array.from(new Set(val));
    }
  }

  // 下拉框数据动态绑定值
  private options: any[] = [];
  // 父组件传入javaType是否是Integer数字类型
  @Prop({ type: String, default: "String" }) private javaType?: any;
  // 父组子组件绑定的下拉框值
  @Model("change") private selectValue?: any;
  // 是否禁用
  @Prop({ type: Boolean, default: false }) private disabled?: boolean;
  // 下拉框选中的值
  private value = [];
  // 下拉框是否被搜索
  private isSearch = false;
  // 监听下拉框选中值的变化，绑定到父组件model的值上
  @Watch("value")
  private watchValue(value: any) {
    this.$emit("change", value.toString());
  }

  // 监听父组件值的变化，动态改变下拉框的值和选中状态
  @Watch("selectValue", { immediate: true })
  private valueChange(value: any) {
    if (value) {
      this.$nextTick(() => {
        this.value = value.split(",");
        let arr: any[] = [];
        for (const str of this.value) {
          arr = arr.concat(
            this.selectList.filter((item: any) => {
              if (item[this.props.value]) {
                if (item[this.props.value].indexOf(str) > -1) {
                  return true;
                }
              }
            })
          );
        }
        this.hiddenList = arr;
        this.options = Array.from(new Set([...this.options, ...arr]));
      });
    } else {
      this.value = [];
    }
  }

  // 动态加载回调，默认一次性传值，下拉到最后一行触发此方法
  loadMore() {
    if (!this.isSearch) {
      this.options = Array.from(
        new Set([...this.options, ...this.tempList.splice(0, 20)])
      );
    }
  }

  // 格式化下拉框，如果是数字类型，将字符串转换为数字
  formatSelectVal(val: any) {
    if (this.javaType === "Integer") {
      return +val;
    } else {
      return val;
    }
  }

  private tempOptions: any[] = [];
  // 下拉框检索方法
  filterMethod(text: any) {
    if (!this.isSearch) {
      this.tempOptions = this.options;
    }
    if (text) {
      const arr: any[] = this.selectList.filter((item: any) => {
        if (item[this.props.label]) {
          if (item[this.props.label].indexOf(text) > -1) {
            return true;
          }
        }
      });
      this.options = Array.from(new Set(arr));
      this.isSearch = true;
    } else {
      this.options = Array.from(
        new Set([...this.tempOptions, ...this.options])
      );
      this.isSearch = false;
      this.hiddenList = [];
    }
  }

  // 失去焦点时恢复下拉框，清除搜索内容
  blurFunction(val: any) {
    if (!val) {
      this.options = Array.from(
        new Set([...this.tempOptions, ...this.options])
      );
      this.isSearch = false;
      this.hiddenList = [];
    }
  }
}
</script>

<style scoped></style>
